/* 
 * File:   CalcularCM.cpp
 * Author: User007
 * 
 * Created on August 12, 2011, 8:31 PM
 */

#include "CalcularCM.h"
#include <cv.h>
#include <stdio.h>
#include "Pixel.h"
#include "ImgMatriz.h"
#include <iostream>
#include "utilMat.h"
#include "EstruturaEquivalente.h"
#include "Posicao.h"
#include <stdlib.h>
#include "CentroMassa.h"
#include <highgui.h>
#include "utilMat.h"
#include "ListaLigada_labelRegiao.h"
#include "Posicao_Struct.h"


CalcularCM::CalcularCM() {   
}

CalcularCM::CalcularCM(const CalcularCM& orig) {
}

CalcularCM::~CalcularCM() {
}

void CalcularCM::ListarCM(IplImage* img) {

    int height = img->height;
    int width = img->width;
    int novoLabel = 10;
    int valor = 10;
    int filho;
    int pai;  
//    matrizRegioes = LoadMatrizRegioes(img);
     ImgMatriz im;
    //Pixel** matrizRegioes = NULL;
    matrizRegioes = NULL;
  
    matrizRegioes = (Pixel**) malloc(width * sizeof (Pixel));
    for (int i = 0; i < width; i++) {
        matrizRegioes[i] = (Pixel*) malloc(height * sizeof (Pixel));
    }

    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            int pixelValor = imgm.getPixel(img, w, h, 0);

            if (pixelValor == 0) {
                //Objeto preto com rotulo = 1 
                matrizRegioes[w][h].setPixel(w, h, pixelValor, 1);
            } else {
                //Fundo com rotulo = 0              
                matrizRegioes[w][h].setPixel(w, h, pixelValor, 0);
            }
        }
    }
    
       
    //Primeira passagem
    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {

            //Verifica se o pixel atual é background ou objeto
           // se for background ignora, se for objeto segue em frente            
             
             if(matrizRegioes[w][h].GetLabel() != 0){  
//                 printf("label: %d - %d,%d ", matrizRegioes[w][h].GetLabel(), w, h);
            
                 //Verifica pixel Esquerda e de Cima
                   // Se nao existem cria novo label
                    if (w == 0 && h == 0) {
                        if (matrizRegioes[w][h].GetLabel() != 0) {
                            novoLabel = novoLabel + valor;
                            matrizRegioes[w][h].SetLabel(novoLabel);                           
                        } else {
                            //Mantem label 0
                        }
                    }//Quando nao existe pixel em cima
                    else if (h == 0 && w != 0) {
                        //Se o pixel da esquerda for background cria novo rotulo
                        if (matrizRegioes[w - 1][h].GetLabel() == 0) {
                            novoLabel = novoLabel + valor;
                            matrizRegioes[w][h].SetLabel(novoLabel);                            
                        }// Se o pixel da esquerda nao é background atribui rotulo
                        else {
                            matrizRegioes[w][h].SetLabel(matrizRegioes[w - 1][h].GetLabel());
                        }
                        //Quando nao existe pixel a esquerda
                    } else if (h != 0 && w == 0) {
                        //Se o pixel de cima for background cria novo rotulo
                        if (matrizRegioes[w][h - 1].GetLabel() == 0) {
                            novoLabel = novoLabel + valor;
                            matrizRegioes[w][h].SetLabel(novoLabel);                            
                        }// Se o pixel da esquerda nao é background atribui rotulo
                    else {
                        matrizRegioes[w][h].SetLabel(matrizRegioes[w][h - 1].GetLabel());
                    }
                }//Se existe pixel a esquerda ou na direita rotula com o mesmo label
                    //Se existem pixel na esquerda e na direita rotula com o menor label
                else if (matrizRegioes[w - 1][h].GetLabel() != 0 || matrizRegioes[w][h - 1].GetLabel() != 0) {
                    //Verifica se existe pixel na esquerda
                    //Se nao existir atribui ao label de cima
                    if (matrizRegioes[w - 1][h].GetLabel() == 0 && matrizRegioes[w][h - 1].GetLabel() != 0) {
                        matrizRegioes[w][h].SetLabel(matrizRegioes[w][h - 1].GetLabel());
                    }//Verifica se existe pixel em cima
                        //Se existir atribui o label da esquerda
                    else if (matrizRegioes[w - 1][h].GetLabel() != 0 && matrizRegioes[w][h - 1].GetLabel() == 0) {
                        matrizRegioes[w][h].SetLabel(matrizRegioes[w - 1][h].GetLabel());
                    }//Se existem os dois, rotule com o menor label
                    else if (matrizRegioes[w - 1][h].GetLabel() != 0 && matrizRegioes[w][h - 1].GetLabel() != 0) {
                        matrizRegioes[w][h].SetLabel(Min(matrizRegioes[w - 1][h].GetLabel(), matrizRegioes[w][h - 1].GetLabel()));
                        //Adiciona esquivalencia na lista de equivalencia
                        //Rotulo menor é o pai, rotulo maior é o filho
                        
                        filho = Max(matrizRegioes[w - 1][h].GetLabel(), matrizRegioes[w][h - 1].GetLabel());
                        pai = matrizRegioes[w][h].GetLabel();
                        //printf("filho %d pai: %d \n", filho, pai);
                        //Max(matrizRegioes[w - 1][h].GetLabel(), matrizRegioes[w][h - 1].GetLabel()), matrizRegioes[w][h].GetLabel()
                        estruturaEQ.add(filho, pai);
                        
                    }
                }//Se os vizinhos são background cria novo label
                else if (matrizRegioes[w - 1][h].GetLabel() == 0 && matrizRegioes[w][h - 1].GetLabel() == 0) {
                    novoLabel = novoLabel + valor;
                    matrizRegioes[w][h].SetLabel(novoLabel);
                }
            }
            //printf("Label add: %d ", matrizRegioes[w][h].GetLabel());
        }
    }
    NextPass(img);
}

void CalcularCM::NextPass(IplImage* img) {
    int height = img->height;
    int width = img->width;

    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {

            //Se não é background
            if (matrizRegioes[w][h].GetLabel() != 0) {
                //Todo filho vira pai                 
                //printf("Label %d vira %d \n", matrizRegioes[w][h].GetLabel(), estruturaEQ.GetPai(matrizRegioes[w][h].GetLabel()));
                matrizRegioes[w][h].SetLabel(estruturaEQ.GetPai(matrizRegioes[w][h].GetLabel()));
                //Cria regiao de label
                cr.addPixelEmLabel(matrizRegioes[w][h].GetLabel());
            }
        }
    }

    for (int i = 0; i < cr.listaLabel.size; i++) {

        int l = cr.listaLabel.get(i)->label;
        int tamanho = cr.listaLabel.get(i)->pixels;

        if (!existeCM(l, img)) {
            //Cria vetor de posicao de centro de massa
            CentroMassa cm;
            //printf("Label: %d tamanho: %d\n", l, tamanho);
            //
            int x = getPosicoesX(l, tamanho, img);
            int y = getPosicoesY(l, tamanho, img);

            posicao_struct pcentro;
            pcentro.x = x;
            pcentro.y = y;
            //printf("Add CM %d,%d\n", x, y);
            listaCentroMassa.add(pcentro);

        }
    }
}

int CalcularCM::getPosicoesX(int label, int tamanho, IplImage* img) {
    int soma = 0;
    int height = img->height;
    int width = img->width;

    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            if (matrizRegioes[w][h].GetLabel() == label) {
                soma = matrizRegioes[w][h].GetX() + soma;
            }
        }
    }
    return soma / tamanho;
}

int CalcularCM::getPosicoesY(int label, int tamanho, IplImage* img) {
    int soma = 0;
    int height = img->height;
    int width = img->width;
    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            if (matrizRegioes[w][h].GetLabel() == label) {
                soma = matrizRegioes[w][h].GetY() + soma;
            }
        }
    }
    return soma / tamanho;
}

bool CalcularCM::existeCM(int label, IplImage* img) {

    int height = img->height;
    int width = img->width;

    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            //Verifica se na label já existe um CM
            if (matrizRegioes[w][h].GetLabel() == label) {
                for (int i = 0; i < listaCentroMassa.size; i++) {
                    //Pega todos os centros de massa da lista de CM criada
                    posicao_struct p = listaCentroMassa.get(i);
                    //Verifica se o ponto é igual a algum elemento da label
                    if (p.x == matrizRegioes[w][h].GetX() && p.y == matrizRegioes[w][h].GetY()) {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

void CalcularCM::CriaImg(IplImage *img) {
    ImgMatriz im;
    for (int h = 0; h < img->height; h++) {
        for (int w = 0; w < img->width; w++) {
            if (matrizRegioes[w][h].GetLabel() != 0) {
                im.setPixel(matrizRegioes[w][h].GetLabel()*1, img, w, h, 0);
                im.setPixel(matrizRegioes[w][h].GetLabel()*5, img, w, h, 1);
                im.setPixel(matrizRegioes[w][h].GetLabel()*2, img, w, h, 2);

            } else {
                im.setPixel(255, img, w, h, 0);
                im.setPixel(255, img, w, h, 1);
                im.setPixel(255, img, w, h, 2);
            }
        }
    }
    cvSaveImage("label.png", img);
}

void CalcularCM::MarcarCM(IplImage *img) {
    ImgMatriz im;
    int x = -1;
    int y = -1;
    for (int h = 0; h < img->height; h++) {
        for (int w = 0; w < img->width; w++) {

            for (int i = 0; i < listaCentroMassa.size; i++) {
                //Se é centro, pinte de preto
                if (listaCentroMassa.get(i).x == w && listaCentroMassa.get(i).y == h) {
                    x = listaCentroMassa.get(i).x;
                    y = listaCentroMassa.get(i).y;
                }
            }
            if (x == w && h == y) {
                im.setPixel(0, img, w, h, 0);
                im.setPixel(0, img, w, h, 1);
                im.setPixel(0, img, w, h, 2);

            } else {
                int r = im.getPixel(img, w, h, 0);
                int g = im.getPixel(img, w, h, 1);
                int b = im.getPixel(img, w, h, 2);
                im.setPixel(r, img, w, h, 0);
                im.setPixel(g, img, w, h, 1);
                im.setPixel(b, img, w, h, 2);
            }
        }
    }
    //cvSaveImage("resultado.png", img);
}






